from info.models import Notice
from department.models import Department, Work
from department.utils.member import assert_member_of as assert_department_member_of
from department.utils import assert_department_permissions, list_departments
from project.models import Project, Participate
from project.utils.member import assert_member_of as assert_project_member_of
from project.utils.permission import assert_project_permissions
from user.models import User
from user.utils.permission import assert_system_permissions
from project.utils.list import list_projects
from django.db.models import Q
from pms.common.utils import flatten_view


def assert_notice_visible(user, notice):
    """ 断言 notice 对 user 可见，否则抛出 PermissionDeny """
    assert isinstance(user, User)
    assert isinstance(notice, Notice)
    if notice.did is not None:  # 部门公告
        assert_department_member_of(user, notice.did)
    elif notice.pid is not None:  # 项目公告
        assert_project_member_of(user, notice.pid)
    # 系统公告对所有用户可见


def notice_view(notice):
    assert isinstance(notice, Notice)
    view = {
        'id': notice.id,
        'title': notice.title,
        'date_time': {
            'year': notice.date_time.year,
            'month': notice.date_time.month,
            'day': notice.date_time.day,
            'hour': notice.date_time.hour,
            'minute': notice.date_time.minute,
            'second': notice.date_time.second
        },
        'content': notice.content
    }
    if notice.did is not None:  # 部门公告
        work = Work.objects.get(uid=notice.uid, rid__did=notice.did)
        view['department'] = {
            'id': notice.did.id,
            'name': notice.did.name,
            'sender': {
                'id': notice.uid.id,
                'name': notice.uid.name,
                'role': {
                    'id': work.rid.id,
                    'name': work.rid.name
                }
            }
        }
    elif notice.pid is not None:  # 项目公告
        participate = Participate.objects.get(uid=notice.uid, rid__pid=notice.pid)
        view['project'] = {
            'id': notice.pid.id,
            'name': notice.pid.name,
            'sender': {
                'id': notice.uid.id,
                'name': notice.uid.name,
                'role': {
                    'id': participate.rid.id,
                    'name': participate.rid.name
                }
            }
        }
    else:  # 系统公告
        view['system'] = {
            'sender': {
                'id': notice.uid.id,
                'name': notice.uid.name,
                'role': {
                    'id': notice.uid.rid.id,
                    'name': notice.uid.rid.name
                }
            }
        }
    return view


def create_notice(user, title, content, department=None, project=None):
    assert isinstance(user, User)
    assert department is None or isinstance(department, Department)
    assert project is None or isinstance(project, Project)
    if department is not None:  # 系统公告
        assert_department_member_of(user, department)
        assert_department_permissions(user.id, department.id, [6])
        notice = Notice(title=title, uid=user, content=content, did=department, pid=None)
    elif project is not None:  # 项目公告
        assert_project_member_of(user, project)
        assert_project_permissions(project.id, user.id, [8])
        notice = Notice(title=title, uid=user, content=content, did=None, pid=project)
    else:  # 系统公告
        assert_system_permissions(user.id, [17])
        notice = Notice(title=title, uid=user, content=content, did=None, pid=None)
    notice.save()
    return notice


def notice_list(user):
    """ 所有对 user 可见的公告的 QuerySet """
    assert isinstance(user, User)
    user_projects = list_projects(user)
    user_departments = list_departments(user)
    return Notice.objects.filter(Q(did__in=user_departments)
                                 | Q(pid__in=user_projects)
                                 | Q(pid=None, did=None)).order_by('date_time')


def update_notice(notice, user, view):
    assert isinstance(notice, Notice)
    assert isinstance(user, User)
    assert user == notice.uid  # 只能修改由自己发布的公告
    if notice.did is not None:
        assert_department_member_of(user, notice.did)
        assert_department_permissions(user.id, notice.did.id, [6])
    elif notice.pid is not None:
        assert_project_member_of(user, notice.pid)
        assert_project_permissions(notice.pid.id, user.id, [8])
    else:
        assert_system_permissions(user.id, [17])
    argv = flatten_view(view, {
        'title': 'title',
        'content': 'content'
    })
    notice.__dict__.update(**argv)
    notice.save()
    return notice
